package jblip.gui.data.channels;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Vector;

class StorageList<T> implements Iterable<T> {

  protected final Vector<T> items_front;

  protected final Vector<T> items_back;

  public StorageList() {
    this(42);
  }

  public StorageList(int size) {
    this.items_front = new Vector<T>(size);
    this.items_back = new Vector<T>(size);
  }

  public void addFirst(T e) {
    items_front.add(e);
  }

  public void addLast(T e) {
    items_back.add(e);
  }

  public boolean contains(Object o) {
    return (items_front.contains(o) || items_back.contains(o));
  }

  public T getFirst() {
    if (isEmpty()) {
      return null;
    }
    if (items_front.isEmpty()) {
      return items_back.get(0);
    } else {
      return items_front.get(items_front.size() - 1);
    }
  }

  public T getLast() {
    if (isEmpty()) {
      return null;
    }
    if (items_back.isEmpty()) {
      return items_front.get(0);
    } else {
      return items_back.get(items_back.size() - 1);
    }
  }

  @Override
  public Iterator<T> iterator() {
    return createIterator(items_front, items_back);
  }

  private Iterator<T> createIterator(final Vector<T> front_list,
      final Vector<T> back_list) {
    return new Iterator<T>() {
      private boolean front = true;

      private int index = front_list.size();

      @Override
      public void remove() {
        throw new UnsupportedOperationException("Removal not supported");
      }

      @Override
      public T next() {
        if (front && index > 0) {
          return front_list.get(--index);
        } else if (front && !back_list.isEmpty()) { /* index == 0 */
          front = false;
          return back_list.get(0);
        } else if (!front && index < back_list.size() - 1) {
          return back_list.get(++index);
        }

        throw new NoSuchElementException("No more elements");
      }

      @Override
      public boolean hasNext() {
        return ((front && (index > 0 || !back_list.isEmpty())) || (!front && index < back_list
            .size() - 1));
      }
    };
  }

  public int size() {
    return items_back.size() + items_front.size();
  }

  public boolean addAll(Collection<? extends T> c) {
    return items_back.addAll(c);
  }
  
  public boolean addAllToFront(Collection<? extends T> c) {
    return items_front.addAll(c);
  }

  public void clear() {
    items_front.clear();
    items_back.clear();
  }

  public boolean isEmpty() {
    return (items_back.isEmpty() && items_front.isEmpty());
  }


  public T get(int index) {
    if (index >= items_front.size()) {
      return items_back.get(index - items_front.size());
    } else {
      return items_front.get(items_front.size() - (index + 1));
    }
  }

  public List<T> subList(final int fromIndex, final int toIndex) {
    ArrayList<T> sub = new ArrayList<T>(toIndex - fromIndex);
    for (int i = fromIndex; i < toIndex; i++) {
      sub.add(get(i));
    }
    return sub;
  }

}
